import { Injectable, BadRequestException, Logger } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { DataSource, Repository } from "typeorm";
import { StallEntity } from "../entities/stall.entity";
import { StallItemEntity } from "../entities/stall-item.entity";
import { StallTradeEntity } from "../entities/stall-trade.entity";
import { CharacterResourcesEntity } from "../entities/character-resources.entity";
import { CharacterInventoryEntity } from "../entities/character-inventory.entity";
import { CharacterMedicineEntity } from "../entities/character-medicine.entity";
import { BasicItemEntity } from "../entities/basic-item.entity";
import { CharacterGemInventoryEntity } from "../entities/character-gem-inventory.entity";
import { CharacterEquipmentInventoryEntity } from "../entities/character-equipment-inventory.entity";
import { PlayerDeputy } from "../entities/player-deputy.entity";
import { DeputyGeneral } from "../entities/deputy-general.entity";

export interface ListTypeFilter {
  type: number; // 0:摊位列表, 1:药品,2:书籍/心法,3:宝石,4:副将/将,5:装备,6:材料
  pageNum?: number;
}

@Injectable()
export class StallService {
  private readonly logger = new Logger(StallService.name);

  constructor(
    private readonly dataSource: DataSource,
    @InjectRepository(StallEntity)
    private readonly stallRepo: Repository<StallEntity>,
    @InjectRepository(StallItemEntity)
    private readonly itemRepo: Repository<StallItemEntity>,
    @InjectRepository(StallTradeEntity)
    private readonly tradeRepo: Repository<StallTradeEntity>
  ) {}

  async getOrCreateMyStall(
    roleId: number,
    roleName: string
  ): Promise<StallEntity> {
    let stall = await this.stallRepo.findOne({ where: { roleId } });
    if (!stall) {
      stall = this.stallRepo.create({
        roleId,
        roleName,
        name: `${roleName}的摊位`,
        pv: 0,
        state: 0,
        type: 1,
        money: 0,
        created_at: new Date(),
        updated_at: new Date(),
      });
      await this.stallRepo.save(stall);
    }
    return stall;
  }

  async rename(roleId: number, newName: string): Promise<void> {
    await this.stallRepo.update(
      { roleId },
      { name: newName, updated_at: new Date() }
    );
  }

  async queryMyStall(roleId: number, roleName: string) {
    const stall = await this.getOrCreateMyStall(roleId, roleName);
    const items = await this.itemRepo.find({ where: { roleId, status: 1 } });
    const things = Array(5).fill(null);
    for (const it of items) {
      if (it.pos >= 0 && it.pos <= 4) {
        things[it.pos] = {
          count: it.count,
          lvl: it.lvl,
          money: it.money,
          name: it.name,
          pos: it.pos,
          role_id: roleId,
          thing_id: it.thingId,
          thing_type: it.thingType,
          weight: it.weight,
        };
      }
    }
    return {
      creation_date: stall.created_at?.toISOString().replace("T", " "),
      money: stall.money,
      name: stall.name,
      pv: stall.pv,
      role_id: stall.roleId,
      role_name: stall.roleName,
      state: stall.state,
      things,
      type: stall.type,
    };
  }

  async prepareShelfFromInventory(
    characterId: number,
    payload: { id: number; pos: number; count: number; money: number }
  ) {
    const { id: itemId, pos, count, money } = payload;
    if (pos < 0 || pos > 4) throw new BadRequestException("无效槽位");
    if (count <= 0) throw new BadRequestException("数量必须>0");
    if (money < 0) throw new BadRequestException("单价必须>=0");

    return this.dataSource.transaction(async (manager) => {
      // 扣背包优先顺序：药品 → 杂物 → 宝石 → 副将
      let source: "medicine" | "inventory" | "gem" | "deputy" = "inventory";
      let name = "";
      let lvl = 0;
      let weight = 0;
      let remaining = 0;

      const med = await manager.findOne(CharacterMedicineEntity, {
        where: { characterId, itemId, status: 1 },
      });
      if (med) {
        if (med.num < count) throw new BadRequestException("药品数量不足");
        name = med.name || "";
        lvl = med.level || 0;
        remaining = med.num - count;
        source = "medicine";
        await manager.update(
          CharacterMedicineEntity,
          { id: med.id },
          {
            num: remaining,
            status: remaining <= 0 ? 0 : 1,
            updated_at: new Date(),
          }
        );
      } else {
        // 杂物
        const inv = await manager.findOne(CharacterInventoryEntity, {
          where: { characterId, itemId, status: 1 },
        });
        if (inv && inv.num >= count) {
          name = inv.name || "";
          lvl = inv.level || 0;
          remaining = inv.num - count;
          await manager.update(
            CharacterInventoryEntity,
            { id: inv.id },
            {
              num: remaining,
              status: remaining <= 0 ? 0 : 1,
              updated_at: new Date(),
            }
          );
          source = "inventory";
        } else {
          // 宝石（唯一ID，count固定为1）
          const gem = await manager.findOne(CharacterGemInventoryEntity, {
            where: { characterId, id: itemId, status: 1 },
          });
          if (gem) {
            if (count !== 1)
              throw new BadRequestException("宝石上架数量只能为1");
            name = gem.name || "";
            lvl = gem.level || 0;
            await manager.update(
              CharacterGemInventoryEntity,
              { id: gem.id },
              { status: 0, updated_at: new Date() }
            );
            source = "gem";
          } else {
            // 副将（按副将ID）
            const pd = await manager.findOne(PlayerDeputy, {
              where: { player_id: characterId, deputy_id: itemId },
            });
            if (!pd) throw new BadRequestException("背包数量不足");
            if (count !== 1)
              throw new BadRequestException("副将上架数量只能为1");
            const dg = await manager.findOne(DeputyGeneral, {
              where: { id: itemId },
              relations: { base: true },
            });
            name = dg?.base?.name || "副将";
            lvl = dg?.lvl || 0;
            await manager.delete(PlayerDeputy, { id: pd.id });
            source = "deputy";
          }
        }
      }

      if (!name) {
        const bi = await manager.findOne(BasicItemEntity, {
          where: { id: itemId },
        });
        name = bi?.name || "";
        weight = bi?.weight || 0;
      }

      // upsert 摊位物品
      let item = await manager.findOne(StallItemEntity, {
        where: { roleId: characterId, pos, status: 1 },
      });
      if (item) {
        // 覆盖为新物品
        item.thingId = itemId;
        item.count = count;
        item.money = money;
        item.name = name;
        item.lvl = lvl;
        item.weight = weight;
        item.thingType =
          source === "medicine"
            ? 1
            : source === "gem"
            ? 3
            : source === "deputy"
            ? 6
            : 4;
        item.updated_at = new Date();
        await manager.save(StallItemEntity, item);
      } else {
        item = manager.create(StallItemEntity, {
          roleId: characterId,
          pos,
          thingId: itemId,
          thingType:
            source === "medicine"
              ? 1
              : source === "gem"
              ? 3
              : source === "deputy"
              ? 6
              : 4, // 1:药,3:石,6:将,4:杂
          name,
          lvl,
          weight,
          count,
          money,
          status: 1,
          created_at: new Date(),
          updated_at: new Date(),
        });
        await manager.save(StallItemEntity, item);
      }
      return true;
    });
  }

  /**
   * 从装备背包上架一件装备（1326）
   */
  async prepareShelfEquipment(
    characterId: number,
    payload: { id: number; pos: number; money: number }
  ) {
    const { id, pos, money } = payload;
    if (pos < 0 || pos > 4) throw new BadRequestException("无效槽位");
    return this.dataSource.transaction(async (manager) => {
      const eq = await manager.findOne(CharacterEquipmentInventoryEntity, {
        where: { id, characterId, status: 1 },
      });
      if (!eq) throw new BadRequestException("装备不存在或不可上架");

      // 下架到摊位：装备背包标记已使用/移出
      await manager.update(
        CharacterEquipmentInventoryEntity,
        { id },
        {
          status: 0,
          updated_at: new Date(),
        }
      );

      const name = eq.name || "";
      const lvl = eq.level || 0;
      const weight = eq.weight || 0;

      let item = await manager.findOne(StallItemEntity, {
        where: { roleId: characterId, pos, status: 1 },
      });
      if (item) {
        item.thingId = id;
        item.thingType = 5; // 装备
        item.count = 1;
        item.money = money;
        item.name = name;
        item.lvl = lvl;
        item.weight = weight;
        item.updated_at = new Date();
        await manager.save(StallItemEntity, item);
      } else {
        item = manager.create(StallItemEntity, {
          roleId: characterId,
          pos,
          thingId: id,
          thingType: 5,
          name,
          lvl,
          weight,
          count: 1,
          money,
          status: 1,
          created_at: new Date(),
          updated_at: new Date(),
        });
        await manager.save(StallItemEntity, item);
      }
      return true;
    });
  }

  /**
   * 从宝石背包上架一颗宝石（1327）
   */
  async prepareShelfGem(
    characterId: number,
    payload: { id: number; pos: number; money: number }
  ) {
    const { id, pos, money } = payload;
    if (pos < 0 || pos > 4) throw new BadRequestException("无效槽位");
    return this.dataSource.transaction(async (manager) => {
      const gem = await manager.findOne(CharacterGemInventoryEntity, {
        where: { id, characterId, status: 1 },
      });
      if (!gem) throw new BadRequestException("宝石不存在或不可上架");

      await manager.update(
        CharacterGemInventoryEntity,
        { id },
        {
          status: 0,
          updated_at: new Date(),
        }
      );

      const name = gem.name || "";
      const lvl = gem.level || 0;

      let item = await manager.findOne(StallItemEntity, {
        where: { roleId: characterId, pos, status: 1 },
      });
      if (item) {
        item.thingId = id;
        item.thingType = 3; // 宝石
        item.count = 1;
        item.money = money;
        item.name = name;
        item.lvl = lvl;
        item.weight = 0;
        item.updated_at = new Date();
        await manager.save(StallItemEntity, item);
      } else {
        item = manager.create(StallItemEntity, {
          roleId: characterId,
          pos,
          thingId: id,
          thingType: 3,
          name,
          lvl,
          weight: 0,
          count: 1,
          money,
          status: 1,
          created_at: new Date(),
          updated_at: new Date(),
        });
        await manager.save(StallItemEntity, item);
      }
      return true;
    });
  }

  /**
   * 取消某槽位上架（1317），并将物品退回对应背包/表
   */
  async unshelfAtPos(characterId: number, pos: number) {
    if (pos < 0 || pos > 4) throw new BadRequestException("无效槽位");
    return this.dataSource.transaction(async (manager) => {
      const record = await manager.findOne(StallItemEntity, {
        where: { roleId: characterId, pos, status: 1 },
      });
      if (!record) return true;

      await this.returnToBag(
        manager,
        characterId,
        Number(record.thingId),
        Number(record.count || 1),
        Number(record.thingType || 4)
      );

      await manager.update(
        StallItemEntity,
        { id: record.id },
        {
          status: 0,
          updated_at: new Date(),
        }
      );
      return true;
    });
  }

  async publish(roleId: number, price: number) {
    const type = price > 0 ? 2 : 1;
    await this.stallRepo.update(
      { roleId },
      { state: 1, type, money: price, updated_at: new Date() }
    );
  }

  async revoke(roleId: number) {
    await this.dataSource.transaction(async (manager) => {
      const items = await manager.find(StallItemEntity, {
        where: { roleId, status: 1 },
      });
      // 物品退回对应背包（按 thingType 分类）
      for (const it of items) {
        await this.returnToBag(
          manager,
          roleId,
          it.thingId,
          it.count,
          it.thingType
        );
      }
      await manager.update(
        StallItemEntity,
        { roleId, status: 1 },
        { status: 0, updated_at: new Date() }
      );
      await manager.update(
        StallEntity,
        { roleId },
        { state: 0, type: 1, money: 0, updated_at: new Date() }
      );
    });
  }

  private async returnToBag(
    manager: any,
    characterId: number,
    itemId: number,
    count: number,
    thingType: number = 4
  ) {
    // 1:药品；3:宝石；6:副将；默认:杂物
    if (thingType === 1) {
      const med = await manager.findOne(CharacterMedicineEntity, {
        where: { characterId, itemId, status: 1 },
      });
      if (med) {
        await manager.update(
          CharacterMedicineEntity,
          { id: med.id },
          { num: med.num + count, updated_at: new Date() }
        );
      } else {
        const bi = await manager.findOne(BasicItemEntity, {
          where: { id: itemId },
        });
        await manager.insert(CharacterMedicineEntity, {
          characterId,
          itemId,
          name: bi?.name || "",
          itemType: 1,
          num: count,
          status: 1,
          pic: bi?.pic || "",
          description: bi?.description || "",
          level: bi?.lv || 0,
          rarity: 1,
          obtainedAt: new Date(),
          created_at: new Date(),
          updated_at: new Date(),
        });
      }
      return;
    }

    if (thingType === 3) {
      // 宝石退回（按唯一ID）
      await manager.update(
        CharacterGemInventoryEntity,
        { id: itemId, characterId },
        { status: 1, updated_at: new Date() }
      );
      return;
    }

    if (thingType === 5) {
      // 装备退回（按装备背包唯一ID）
      await manager.update(
        CharacterEquipmentInventoryEntity,
        { id: itemId, characterId },
        { status: 1, updated_at: new Date() }
      );
      return;
    }

    if (thingType === 6) {
      // 副将退回（恢复到玩家副将列表）
      const exists = await manager.findOne(PlayerDeputy, {
        where: { player_id: characterId, deputy_id: itemId },
      });
      if (!exists) {
        await manager.insert(PlayerDeputy, {
          player_id: characterId,
          deputy_id: itemId,
          pos: 0,
          created_at: new Date(),
          updated_at: new Date(),
        });
      }
      return;
    }

    // 默认杂物背包
    const exists = await manager.findOne(CharacterInventoryEntity, {
      where: { characterId, itemId, status: 1 },
    });
    if (exists) {
      await manager.update(
        CharacterInventoryEntity,
        { id: exists.id },
        { num: exists.num + count, updated_at: new Date() }
      );
    } else {
      const bi = await manager.findOne(BasicItemEntity, {
        where: { id: itemId },
      });
      await manager.insert(CharacterInventoryEntity, {
        characterId,
        itemId,
        name: bi?.name || "",
        itemType: bi?.lv || 0,
        num: count,
        status: 1,
        pic: bi?.pic || "",
        description: bi?.description || "",
        level: bi?.lv || 0,
        rarity: 1,
        obtainedAt: new Date(),
        created_at: new Date(),
        updated_at: new Date(),
      });
    }
  }

  async getStallInfo(stallId: number) {
    const stall = await this.stallRepo.findOne({ where: { roleId: stallId } });
    if (!stall) throw new BadRequestException("摊位不存在");
    const items = await this.itemRepo.find({
      where: { roleId: stallId, status: 1 },
    });
    const things = Array(5).fill(null);
    for (const it of items) {
      if (it.pos >= 0 && it.pos <= 4) {
        things[it.pos] = {
          count: it.count,
          lvl: it.lvl,
          money: it.money,
          name: it.name,
          pos: it.pos,
          role_id: stall.roleId,
          thing_id: it.thingId,
          thing_type: it.thingType,
          weight: it.weight,
        };
      }
    }
    return {
      creation_date: stall.created_at?.toISOString().replace("T", " "),
      money: 0,
      name: stall.name,
      pv: stall.pv,
      role_id: stall.roleId,
      role_name: stall.roleName,
      state: stall.state,
      things,
      type: stall.type,
    };
  }

  async listByType(filter: ListTypeFilter) {
    const page = Number(filter.pageNum || 0);
    if (filter.type === 0) {
      const list = await this.stallRepo.find({
        where: { state: 1 },
        take: 50,
        skip: page * 50,
        order: { pv: "DESC" },
      });
      return list.map((s) => ({
        money: 0,
        name: s.name,
        pv: s.pv,
        role_id: s.roleId,
        state: s.state,
        type: 1,
      }));
    }
    // 其他类型：聚合所有上架中的 items（简单实现：按基础物品ID分类）
    const items = await this.itemRepo.find({
      where: { status: 1 },
      take: 100,
      skip: page * 100,
    });
    return items.map((it) => ({
      money: it.money,
      name: it.name,
      role_id: it.roleId,
      thing_id: it.thingId,
      type: 1,
    }));
  }

  async buy(
    buyerId: number,
    payload: { stallId: number; pos: number; thingId: number; count: number }
  ) {
    const { stallId, pos, thingId, count } = payload;
    if (count < 0) throw new BadRequestException("数量无效");

    return this.dataSource.transaction(async (manager) => {
      const stall = await manager.findOne(StallEntity, {
        where: { roleId: stallId },
      });
      if (!stall || stall.state !== 1)
        throw new BadRequestException("摊位未发布");

      if (stall.type === 2) {
        // 打包购买：忽略 pos/count/thingId，按整摊价格一次性购买
        const items = await manager.find(StallItemEntity, {
          where: { roleId: stallId, status: 1 },
        });
        if (items.length === 0) throw new BadRequestException("无在售物品");
        await this.paySilver(manager, buyerId, stall.money);
        // 加入买家背包
        for (const it of items) {
          await this.returnToBag(manager, buyerId, it.thingId, it.count);
        }
        // 标记售出，记录交易
        await manager.update(
          StallItemEntity,
          { roleId: stallId, status: 1 },
          { status: 0, updated_at: new Date() }
        );
        for (const it of items) {
          const trade = manager.create(StallTradeEntity, {
            sellRoleId: stallId,
            buyRoleId: buyerId,
            thingId: it.thingId,
            thingType: it.thingType,
            thingName: it.name,
            count: it.count,
            money: stall.money,
            created_at: new Date(),
            updated_at: new Date(),
          });
          await manager.save(StallTradeEntity, trade);
        }
        return { msg: `打包购买成功, 共计 ${stall.money} 两` };
      }

      // 普通购买：校验指定槽位物品
      const item = await manager.findOne(StallItemEntity, {
        where: { roleId: stallId, pos, status: 1 },
      });
      if (!item || item.thingId !== thingId)
        throw new BadRequestException("商品不存在");
      const buyCount = count > 0 ? count : item.count;
      if (buyCount > item.count) throw new BadRequestException("数量不足");
      const total = item.money * buyCount;
      await this.paySilver(manager, buyerId, total);

      // 发货到买家背包
      await this.returnToBag(manager, buyerId, item.thingId, buyCount);

      // 更新摊位库存
      const left = item.count - buyCount;
      if (left <= 0) {
        await manager.update(
          StallItemEntity,
          { id: item.id },
          { status: 0, updated_at: new Date() }
        );
      } else {
        await manager.update(
          StallItemEntity,
          { id: item.id },
          { count: left, updated_at: new Date() }
        );
      }

      // 交易记录
      const trade = manager.create(StallTradeEntity, {
        sellRoleId: stallId,
        buyRoleId: buyerId,
        thingId: item.thingId,
        thingType: item.thingType,
        thingName: item.name,
        count: buyCount,
        money: total,
        created_at: new Date(),
        updated_at: new Date(),
      });
      await manager.save(StallTradeEntity, trade);

      return { msg: `您成功购得 ${buyCount} 个${item.name},共计 ${total} 两` };
    });
  }

  private async paySilver(manager: any, characterId: number, amount: number) {
    if (amount <= 0) return;
    const res = await manager.findOne(CharacterResourcesEntity, {
      where: { characterId },
    });
    if (!res || res.silver < amount)
      throw new BadRequestException("您的银两不足,无法购买此商品.");
    await manager.update(
      CharacterResourcesEntity,
      { characterId },
      { silver: res.silver - amount, updated_at: new Date() }
    );
  }

  async listTrades(stallId: number) {
    const list = await this.tradeRepo.find({
      where: { sellRoleId: stallId },
      take: 50,
      order: { id: "DESC" },
    });
    return list.map((t) => ({
      buy_id: t.buyRoleId,
      buy_name: "", // 暂缺角色名，client未用
      count: t.count,
      creation_date: t.created_at?.toISOString().replace("T", " "),
      money: t.money,
      sell_id: t.sellRoleId,
      thing_id: t.thingId,
      thing_name: t.thingName,
      thing_type: t.thingType,
    }));
  }

  /**
   * 我的在架列表（用于 1316）
   */
  async listMyShelf(roleId: number, pageNum: number = 0) {
    const take = 50;
    const skip = pageNum * take;
    const items = await this.itemRepo.find({
      where: { roleId, status: 1 },
      order: { pos: "ASC", id: "DESC" },
      take,
      skip,
    });
    const list = items.map((it) => ({
      pos: it.pos,
      role_id: it.roleId,
      thing_id: it.thingId,
      thing_type: it.thingType,
      name: it.name,
      lvl: it.lvl,
      count: it.count,
      money: it.money,
      weight: it.weight,
    }));
    return { list, page: pageNum + 1, sum: list.length };
  }

  /**
   * 我的出售记录（分页）- 用于 1322
   */
  async listMySalesPaged(roleId: number, pageNum: number = 0) {
    const take = 50;
    const skip = pageNum * take;
    const [rows, total] = await this.tradeRepo.findAndCount({
      where: { sellRoleId: roleId },
      order: { id: "DESC" },
      take,
      skip,
    });
    const list = rows.map((t) => ({
      buy_id: t.buyRoleId,
      buy_name: "",
      count: t.count,
      creation_date: t.created_at?.toISOString().replace("T", " ") || "",
      money: t.money,
      sell_id: t.sellRoleId,
      thing_id: t.thingId,
      thing_name: t.thingName,
      thing_type: t.thingType,
    }));
    return { list, page: pageNum + 1, sum: total };
  }

  /**
   * 我的购买记录（分页）- 用于 1323
   */
  async listMyPurchases(roleId: number, pageNum: number = 0) {
    const take = 50;
    const skip = pageNum * take;
    const [rows, total] = await this.tradeRepo.findAndCount({
      where: { buyRoleId: roleId },
      order: { id: "DESC" },
      take,
      skip,
    });
    const list = rows.map((t) => ({
      buy_id: t.buyRoleId,
      sell_id: t.sellRoleId,
      thing_id: t.thingId,
      thing_name: t.thingName,
      thing_type: t.thingType,
      count: t.count,
      money: t.money,
      creation_date: t.created_at?.toISOString().replace("T", " ") || "",
    }));
    return { list, page: pageNum + 1, sum: total };
  }
}
